//
//  HttpService.m
//  aloqa
//
//  Created by mkoo sun on 12-8-24.
//  Copyright (c) 2012年 exodus. All rights reserved.
//

#import "HttpService.h"
#import "Cordova/JSONKit.h"
#import "ServiceManager.h"
#import "SessionWatcher.h"
#import "LoginController.h"
#import "AppDelegate.h"

BOOL isReLogin = NO;

//-------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------
@implementation HttpTask

@synthesize owner;
@synthesize handler;
@synthesize listener;
//@synthesize isCompleted;
@synthesize status;
@synthesize url;
@synthesize method;
@synthesize body;
@synthesize header;
@synthesize wait;
@synthesize oldSession;
@synthesize retryTimes;

- (id)init
{
    self = [super init];
    if (self) {
        handler = [[NetHandler alloc]init];
//        isCompleted = NO;
        self.status = TASK_REQUEST;
        self.retryTimes = 0;
    }
    return self;
}

- (void)dealloc
{
    self.handler = nil;
    self.listener = nil;
    self.url = nil;
    self.method = nil;
    self.body = nil;
    self.header = nil;
    self.oldSession = nil;
    
    [super dealloc];
}

-(void) httpError
{
    if(listener)
    {
        [listener result:500 headers:Nil body:Nil];
    }
    
    self.status = TASK_COMPLETED;
//    self.isCompleted = YES;
}

-(void) httpTimeOut
{
    if(listener)
    {
        [listener result:500 headers:Nil body:Nil];   
    }
    
//    self.isCompleted = YES;
    self.status = TASK_COMPLETED;
}

-(void) httpComplete:(NetResponse*) response
{
//    NSString* log = [NSString stringWithFormat:@"response %d: %@", [response code], [response result]];
//    [self log:5 name:@"Http Service" message:log];   
    NSDictionary* headers = [response headers];
    
    for(id key in headers)
    {
        if( [[key lowercaseString] isEqualToString:@"x-ods-status"] )
        {
            NSString* value = [headers objectForKey:key];
            int statusCode = [value intValue];
            if(statusCode == 401)
            {
                User* user = [GlobalUtil getInstance].user;
                self.oldSession = user.session;
                
                self.status = TASK_NEED_RETRY;
                self.retryTimes ++;
                
                if(self.retryTimes >= 3)
                {
                    self.status = TASK_COMPLETED;
                    [self httpError];
                    return;
                }
                
                if(isReLogin == NO)
                {
                    isReLogin = YES;
                    SessionService* serv = [[ServiceManager getInstance] getService:SESSION_SERVICE];
                    [serv relogin:self];
                }
                
                return;
            }
        }
        
        if( [ [key lowercaseString] isEqualToString:@"aloca-state"] )
        {
            NSString* value = [headers objectForKey:key];
            
            [ ((HttpService*)owner) parseState:value];
        }
    }
    
    if(listener)
    {
        [listener result:[response code] headers:[response headers] body:[response resultBytes]];
    }
    
//    self.isCompleted = YES;
    status = TASK_COMPLETED;
}

-(void) onSuccess:(int) code  action:(NSString*) aciton message:(NSString*)message
{
//    [owner updateUncompleteTask];
}

-(void) onError:(int) code  action:(NSString*) aciton message:(NSString*)message
{
    isReLogin = NO;
    
    [self httpError];
    
    LoginController *p=[[LoginController alloc] initWithNibName:@"LoginController" bundle:nil];
    
    AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    [(UINavigationController *)delegate.window.rootViewController pushViewController:p animated:YES];
    [p release];
    
    UIAlertView* alertView = [[UIAlertView alloc]initWithTitle:@"请重新登录" message:@"session失效，请重新登录" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
    [alertView show];
    [alertView release];
}

-(void) onLogining
{
}

-(void) onLogon:(User*) user
{
    isReLogin = NO;
    
    [owner updateUncompleteTask];
}

-(void) onFailedLogin: (int) code message:(NSString*) message
{
}

@end

//-------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------

@implementation HttpService
@synthesize httpTaskList;

//-------------------------------------------------------------------------------------------
- (id)init
{
    self = [super init];
    if (self) {
        providers = [[NSMutableArray alloc]init];
    }
    return self;
}

- (void)dealloc
{
    [providers release];
    providers = nil;
    self.httpTaskList = nil;    
    [super dealloc];
}

//-------------------------------------------------------------------------------------------
-(NSString*)getState
{
    NSMutableDictionary* states = [[NSMutableDictionary alloc]init];
    
    for(id provider in providers)
    {
        NSString* name = [provider getName];
        NSString* state = [provider getState];
        NSObject* stateObj = [state objectFromJSONString];
        
        if(name == Nil)
            continue;
        
        [states setValue:stateObj forKey:name];
        
        /*
        NSData* data = [state JSONData];
        NSDictionary* dic = [data objectFromJSONData];
        if(dic)
        {
            [states setValue:dic forKey:name];
        }
        else {
            [states setValue:state forKey:name];
        }
        */
    }
    
    NSString* result = [states JSONString];
    [states release];
    return result;
}

-(void)parseState:(NSString*)content
{
//    NSData* data = [content dataUsingEncoding:NSUTF8StringEncoding];
//    
//    NSDictionary* states = [data objectFromJSONData];
    
    NSDictionary* states = [content objectFromJSONString];
    
    EventService* eventServ = [[ServiceManager getInstance]getService:EVENT_SERVICE];
    
    for(id key in states)
    {
        NSString* name = key;
        NSArray* value = [states objectForKey:key];
        NSString* state = [value JSONString];
        //NSString* state = [states objectForKey:key];
        
        NSString* global_event_id = @"org.exodus.aloqa.state";
        NSString* event_id = [NSString stringWithFormat:@"org.exodus.aloqa.state.%@", name];
        
        [eventServ signEvent:event_id param1:name param2:state];
        [eventServ signEvent:global_event_id param1:name param2:state];
    }
}

-(void)updateUncompleteTask
{
    if(httpTaskList==nil)
    {
        httpTaskList = [[NSMutableArray alloc]init];
    }
    else
    {
        for(int i=0; i<httpTaskList.count; i++)
        {
            HttpTask* task = [httpTaskList objectAtIndex:i];
            if(task.status == TASK_NEED_RETRY)
            {
                task.status = TASK_REQUEST;
                
                NSMutableString* newUrl = [[NSMutableString alloc]initWithString:task.url];
                
                User* user = [GlobalUtil getInstance].user;
                
                BOOL replacedSession = NO;
                
                if(task.oldSession)
                {
                    NSRange range = [newUrl rangeOfString:task.oldSession options:NSBackwardsSearch];
                    if (range.length >0 )
                    {
                        [newUrl replaceCharactersInRange:range withString:user.session];
                        
                        replacedSession = YES;
                    }
                }
                
                if(!replacedSession)
                {
                    NSRange range = [newUrl rangeOfString:@"session=" options:NSBackwardsSearch];
                    
                    if(range.length > 0)
                    {
                        int startPos = range.location+range.length;
                        int length = newUrl.length - (range.location + range.length);
                        
                        NSRange nextPos = [newUrl rangeOfString:@"&" options:0 range:NSMakeRange(startPos, newUrl.length - startPos)];
                        
                        if(nextPos.length>0)
                        {
                            length = nextPos.location - (range.location + range.length);
                            
                        }
                        NSRange sessionRange = NSMakeRange(startPos, length);
                        [newUrl replaceCharactersInRange:sessionRange withString:user.session];
                    }
                }
                
                if([[task.method lowercaseString] isEqualToString:@"get"] )
                {
                    if(!task.wait)
                    {
                        [[task handler] doHttpGet:newUrl header:task.header delegate:task];
                    }
                    else {
                        [[task handler] doHttpGetSync:newUrl header:task.header delegate:task];
                    }
                }
                else {
                    if(!task.wait)
                    {
                        [[task handler] doHttpPost:newUrl header:task.header body:task.body delegate:task];
                    }
                    else {
                        [[task handler] doHttpPostSync:newUrl header:task.header body:task.body delegate:task];
                    }
                }
            }
        }
    }
}

//-------------------------------------------------------------------------------------------
-(void)request:(NSString*)url method:(NSString*)method headers:(NSDictionary*)headers body:(NSData*)body listener:(id<HttpListener>)listener wait:(BOOL)wait
{
    if(httpTaskList==nil)
    {
        httpTaskList = [[NSMutableArray alloc]init];
    }
    else
    {
        for(int i=0; i<httpTaskList.count; i++)
        {
            HttpTask* subTask = [httpTaskList objectAtIndex:i];
            if(subTask.status == TASK_COMPLETED)
            {
                [httpTaskList removeObject:subTask];
                i--;
            }
        }
    }
    
    HttpTask* task = [[HttpTask alloc]init];
    [self.httpTaskList addObject:task];
    task.listener = listener;
    task.owner = self;
    
    NSMutableDictionary* newHeader = [[NSMutableDictionary alloc]init];
    if(headers)
    {
        for(id key in headers)
        {
            [newHeader setValue:[headers objectForKey:key] forKey:key];
        }
    }
    
    NSString* value = [self getState];
    [newHeader setValue:value forKey:@"aloca-state"];
    if([newHeader objectForKey:@"Content-Type"]==nil)
    {
        [newHeader setValue:@"text/plain;charset=UTF-8" forKey:@"Content-Type"];
    }

    task.method = method;
    task.url = url;
    task.header = newHeader;
    task.wait = wait;
    task.body = body;
    
    if([[method lowercaseString] isEqualToString:@"get"] )
    {
        if(!wait)
        {
            [[task handler] doHttpGet:url header:newHeader delegate:task];
        }
        else {
            [[task handler] doHttpGetSync:url header:newHeader delegate:task];
        }
    }
    else {
        if(!wait)
        {
            [[task handler] doHttpPost:url header:newHeader body:body delegate:task];                                      
        }
        else {
            [[task handler] doHttpPostSync:url header:newHeader body:body delegate:task];
        }
    }
    
    //NSString* log = [NSString stringWithFormat:@"execute request: %@ %@", method, url];
    //[self log:5 name:@"Http Service" message:log];

    [task release];
    [newHeader release];
}

//-------------------------------------------------------------------------------------------
-(int)registerStateProvider:(id<StateProvider>)provider
{
    [providers addObject:provider];
    int index = [providers indexOfObject:provider];
    return index;
}

//-------------------------------------------------------------------------------------------
-(void)unregisterStateProvider:(int)stub
{
    [providers removeObjectAtIndex:stub];
}

//-------------------------------------------------------------------------------------------
- (void) log:(int)level name:(NSString*)name message:(NSString*)message
{
    Log* logService = [[ServiceManager getInstance]getService:LOG_SERVICE];
    [logService log:level name:name message:message];
}

@end
